// Hardware Interface Library
//


// This function resets any encoder struct
//
void InitEncoderStateStruct(EncoderStateStruct * ENCODER)
{
	ENCODER->last_position=0b11;
	ENCODER->current_position=0b11;
	ENCODER->direction=ENC_REST;
}


// Encoder Engine.
//
signed int ENC_Scan( EncoderStateStruct * ENCODER )
{
	//
	// First we start from where we were last time
	//
	switch(ENCODER->last_position)
	{
		case 0b11: // Rest state
		{
			ENCODER->direction=ENC_REST;
			if(ENCODER->current_position == 0b01) // Going Clockwise
			{
				ENCODER->direction=ENC_CW;
				ENCODER->last_position=ENCODER->current_position;
				break;
			} else

			if(ENCODER->current_position == 0b10) // Going Counterclockwise
			{
				ENCODER->direction=ENC_CCW;
				ENCODER->last_position=ENCODER->current_position;
				break;
			} else

			if(ENCODER->current_position == 0b00)
			{
				ENCODER->direction=ENC_ERROR;
				ENCODER->last_position=ENCODER->current_position;
			}
			break; 
		}

		case 0b01: // Left edge
		{
			ENCODER->direction=ENC_REST;

			if(ENCODER->current_position == 0b00)
			{
				ENCODER->direction=ENC_CW;
				ENCODER->last_position=ENCODER->current_position;
				break;
			} else

			if(ENCODER->current_position == 0b11)
			{
				ENCODER->direction=ENC_CCW;
				ENCODER->last_position=ENCODER->current_position;
				break;
			} else

			if(ENCODER->current_position == 0b10)
			{
				ENCODER->direction=ENC_ERROR;
				ENCODER->last_position=ENCODER->current_position;
			}
			break; 
		}

		case 0b00: // Center Position
		{
			ENCODER->direction=ENC_REST;

			if(ENCODER->current_position == 0b10)
			{
				ENCODER->direction=ENC_CW;
				ENCODER->last_position=ENCODER->current_position;
				break;
			} else

			if(ENCODER->current_position == 0b01)
			{
				ENCODER->direction=ENC_CCW;
				ENCODER->last_position=ENCODER->current_position;
				break;
			} else
			if(ENCODER->current_position == 0b11)
			{
				ENCODER->direction=ENC_ERROR;
				ENCODER->last_position=ENCODER->current_position;
			}
			break;
		}

		case 0b10: // Right Edge
		{
			ENCODER->direction=ENC_REST;

			if(ENCODER->current_position == 0b11)
			{
				ENCODER->direction=ENC_CW;
				ENCODER->last_position=ENCODER->current_position;
				break;
			} else

			if(ENCODER->current_position == 0b00)
			{
				ENCODER->direction=ENC_CCW;
				ENCODER->last_position=ENCODER->current_position;
				break;
			} else

			if(ENCODER->current_position == 0b01)
			{
				ENCODER->direction=ENC_ERROR;
				ENCODER->last_position=ENCODER->current_position;
			}
			break;
		}
	}

	if((ENCODER->direction == ENC_CW) && (ENCODER->current_position==0b11)) return 1;
	if((ENCODER->direction == ENC_CCW) && (ENCODER->current_position==0b11)) return -1;
	return 0;
}


// 74xx595 Shift Register Reset Engine
//
void reset595( void )
{
	output_low(SER);
	output_low(SCK);	
	output_low(RCK);
	output_low(SCL);
	delay_cycles(2);
	output_high(SCL);
}


// Shift Register Loading Function
//
void ShiftOut(char DatToWrite)
{
	int place;

	for(place=0; place < 8; place++)
	{
		if(DatToWrite & 1) output_high(SER);
		else output_low(SER);
		delay_cycles(4);

		//
		//  Clock bit into place
		//
		output_high(SCK);
		delay_cycles(4);
		output_low(SCK);
		delay_cycles(4);

		//
		// Move to the next bit for the next pass
		//
		DatToWrite=DatToWrite >> 1;
	}

	//
	// Put the final result into the register
	//
	output_high(RCK);
	delay_cycles(4);
	output_low(RCK);
	delay_cycles(4);
}


// Set all unused pins to a definite logic level to enhance noise immunity.
//
void SetUnusedPins( void )
{
						// Some sensitivity to what's on the
						// PICs pins has been noticed
	output_low(PIN_B5);	// so every unused pin is being set low.
	output_low(PIN_B4); // It would be better if each pin was pulled
						// by a resistor but that costs money.
}

// Function to read the encoders instantaneous state
//
char ENC_Read(void)
{
	char
		sample1=99,
		sample2=0;

	while(sample1 != sample2)
	{
		sample1 = input( ENC_A ) << 1 | input( ENC_B );
		delay_us(250);
		sample2 = input( ENC_A ) << 1 | input( ENC_B );
		delay_us(250);
	}

	return sample1;
}

void Set_Rel( short state )
{
	output_bit(RELAY, state);
}

short TrigState( void )
{
	return( !input( TRIGGER ) ) ;
}

short EncButton( void )
{
	return( !input( BTN ) );
}

PushType MultiPushButton( void )
{
	short sample;
	PushType push;

	static long int push_duration=0;

	sample = EncButton();

	push = off;

	if(!sample) push_duration=0; 
	else
	{
		push = on;
		push_duration++;
		if(push_duration >= LONGPUSH) push = push_held;
	}
	return push;
}

void WaitPB_Release(void)
{
	while( EncButton() );
	delay_ms(100);
}